import com.mysql.cj.jdbc.MysqlDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Scanner;

public class JDBCInsert {
    public static void main(String[] args) throws SQLException {
        Scanner scanner = new Scanner(System.in);

         // JDBC 需要通过以下步骤来完成开发。
        // 1 . 创建并初始化一个 数据源  （描述数据库服务器在哪里） (DataSource)

        DataSource dataSource = new MysqlDataSource();  // 向上转型
        // 用一个父类引用指向一个子类对象
        ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/java_110?characterEnding=utf-8&&useSSL=false"); //setUrl() 这个方法是子类有的父类没有 ，所以要转回来 向下转型
        ((MysqlDataSource)dataSource).setUser("root"); //需要有用户名和密码
        ((MysqlDataSource)dataSource).setPassword("Zuochuyao1314."); //密码
        // 这几个东西都设置进去才能访问数据库服务器
        // 用户名就默认是 root
        // 密码呢就是你安装的时候数据库密码是啥就设置成啥

        // 当前这个代码只是设置数据源，描述数据库服务器在哪~，还没有真正和数据库服务器链接

        // jdbc:mysql://127.0.0.1:3306/java_110?characterEnding=utf-8&&useSSL=false // 这里面的东西后面详解
        // 这一段最好是复制粘贴就好了

        // jdbc 是固定的   mysql:是看你用的啥数据库
        // 127.0.0.1 表示宏ip， mysql数据库是一个“客户端服务器"结构的程序。客户端和服务器之间通过网络来通信
        // 网络上确定一个主机的位置就是通过ip地址来确定的 （咱们都是写作127.0.0.1  叫做环回ip，表示你自己当前的主机。因为咱们的
        // 数据库客户端（现在写的jdbc代码），数据库服务器（之前装存数据的服务）是在同一台主机上）
        // 3306 叫做端口号  端口用来区分应用程序 数据库服务器默认端口就是3306
        // java_110 这个是我们自己创建的数据库名 (create databases 数据库名) (表示你要访问的哪一个资源)
        //characterEnding=utf-8 表示字符集 当前使用的字符集是utf-8
        // useSSL=false 表示不加密 SSL是一个加密协议



        // 写法二：
        // MysqlDataSource dataSource = new MysqlDataSource();
        // dataSource.setUrl();  // 这么写是完全ok的 上面呢样写是因为java圈子里流行这样写

        //Url 表示 唯一资源定位符  ~~描述网络上某个资源所在的位置~~

        // 2. 和数据库服务器建立一个链接

        // 接下来进行数据库的链接
      Connection connection = dataSource.getConnection(); //这个方法就是建立链接的方法
        //throws SQLException  // 用Connection来接收 ， Connection必须选择是 java.sql的
        // 这里面为什么会报异常呢
        // 这里就涉及到受查异常和非受查异常
        // 受查异常 必须要显示处理
        // 非受查异常 不显示处理也没关系
        // 这里的异常就是受查异常

        // 3.从控制台读取用户的输入内容
        System.out.println("请输入学生姓名:");
        String name = scanner.nextLine();
        System.out.println("请输入学号:");
        int id = scanner.nextInt();

        // 4. 构造一个sql语句
        // 接下来就插入数据

        //String sql = "insert into student value(1,'张三')";  // 这个单单只是字符串sql
        //String sql = "insert into student value("+ id +",'"+ name +"')";  // 字符串拼接进行写入（简单粗暴的写法）,这样写也不安全会有sql注入

        // 更好的写法是借助这个PrepareStatement 的拼装功能来实现
        String sql = "insert into student value(?,?)"; //此出的？表示一个占位符用于后序代码的替换


        // 会发现使用代码来操作数据库 还是靠sql语句！！！，只不过是换成代码来使用sql了

        // 当前的sql语句是写死的（硬编码）
        // 更合适的做法，就是把数据通过其他方式让用户输入
        // 用控制台输入

        // 提前预编译数据库 (让服务器做的工作简单一些，压力就会少)
        PreparedStatement statement = connection.prepareStatement(sql);  // 这一句PreparedStatement是对sql语句进行预编译


        // 然后在这里加入
        statement.setInt(1,id); // 1 是第一个问号  2 是第二个问号
        statement.setString(2,name);  // 这两行的作用就是把占位符替换成指定的值
        System.out.println(statement); // 这个打印是要夹在拼接数据之后

        // 5. 执行sql语句
        int ret = statement.executeUpdate();  // 这个操作就是真正执行了 返回类型是int型
        // 把sql语句（预编译过的）发送给数据库服务器，由服务器做出相应
        // insert delete update 这几个操作都是用 executeUpdate方法  返回类型是int型 =》 表示影响到的行数
        // 而 select 使用的是 executeQuery 方法
        System.out.println("ret = "+ret);

        // 6.释放必要的资源
        // 需要释放两个地方
        statement.close(); // 构造的sql语句
        connection.close(); // 构造的sql链接

        // 详细解释一下释放资源
        // 一定是先释放语句在释放链接
        // 换句话说就是谁是先创建的谁就后释放
        // 创建和释放是相反的

        // 当前使用的JDBC是使用DataSource这样的方式来编写的
        // 还有一种写法是DriverManager，通过反射的方式加载 驱动包 中的类，进一步进行后续操作的~~ （这个不推荐的）

        // 这里的代码刚开始接触会觉得很麻烦 涉及到很多的类，新的方法，新的概念
        // 但是多写几次就会发现，这里的代码就是固定的套路
        // 框架是一直在变得
        // jdbc是不变的 ！

    }
}
